#include "main.h"
#include "sys.h"
#include "delay.h"
#include "stm32f7xx.h"                  // Device header
#include <stdio.h> 
#include <stdlib.h> 
#include "SD_write.h"

#include "usb_device.h"
#include "usbd_cdc.h"
#include "sdmmc_sdcard.h"
#include "w25qxx.h"
#include "ff.h"
#include "ftl.h" 
//#include "usmart.h"
#include "malloc.h"
#include "debug.h"
#include "Pic_Process.h"
#include "usart.h"
#include "IOConfig.h"

#include "SSD2832.h"
#include "SPI_INIT.h"
#include "ics307.h"

#include "fsmc.h"
#include "InternalFlash.h"
#include "timer.h"
#include <ctype.h>						 /* Character functions                */
//#include "rl_fs.h"               		 /* CMSIS RTOS definitions             */ 
//#include "cmsis_os.h"         		 /* FileSystem definitions             */
#include "adc_volt.h"
#include "w25qxx.h"
#include "mtp_pwm.h"
#include "ad5274_5271.h"
#pragma  diag_suppress 870
__ALIGN_BEGIN USBD_HandleTypeDef    USB_OTG_dev __ALIGN_END ;
u8(*pf)(char*,u32);
FRESULT res = FR_NOT_READY;
FATFS USB_fatfs,SD_fatfs,NAND_fatfs;
FIL usb_file,sd_file,sd_file1,NAND_file,NAND_file1;
DIR dir;

u8  disk = NO_Disc;
u8  Err_code = None_Err;                                    //错误代码       
u8  CFG_Valid_flag = 0;                                     //更新时 CFG文件有效标志
u32 Length = 0;
u32 Delay_time = 0;
u32 Count_time = 0;
u8  FSMC_Send_Flag = 0;
u8 DUAL_SPI_MODE_AUTO;
u8  Loaded_BMPNum = 0;                                     //已载入的BMP图片数量
char valid_FileNames [File_NUM_MAX][File_NAME_MAX];      //SD卡有效分辨率的BMP图片名称
char **CFG_N=NULL;
char CFG_Name[10][30] = {0};
int CFG_Num=0;
extern u16 RDAC;			//初始化VCI用
extern u16 RDAC_VDDIO;			//初始化VDDIO用
extern u16 RDAC_DVDD;
extern u8 CFGorBMP;
extern u8 BMPnums;
extern u32 Receive_CFG_Length ;
extern u8  Receive_CFG_Flag1 ;
extern const u16 AD_Value1[8];
extern const u16 AD_Value2[8];
extern const u16 AD_Value3[8];
u32 CFG_Lenth=0;
u8  Key_vaild = 1,Key_Auto = 0;
u16 LED_Flick=0;
u32 Pure_Color_Table[8]={WHITE,RED,GREEN,BLUE,YELLOW,PINK,CYAN,BLACK};
u8  DDR_Addr_ID=0;
u8  Auto_Flag = 0;
u8  SSD2832_SCM_Flag=0;
u16 SSD2832_ID=0;
u8 FPGA_ID=0;
u16 flash_ID=0;
volatile u8 BIN_Len[4]={0};
u16 DataFlag=0,Page=0;
/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */

void Generate_cfg(USBD_HandleTypeDef *pdev,u32 Address)
{
	u16 temp,temp1;
	j=0;      
	FLASH_If_Read(Address, buffer1, 0,2048);	//?FLASH???Timing??????,?????FPGA
	for(i=0;i<16;i++)
	{
		buffer[i*4]		= (u8)(buffer1[i]>>24);
		buffer[(i*4)+1] = (u8)(buffer1[i]>>16);
		buffer[(i*4)+2] = (u8)(buffer1[i]>>8);
		buffer[(i*4)+3] = (u8)(buffer1[i]);
	}
	if((buffer[Timing_Data_Max-1] >= 0xA0))		//Mipi??? ??,????FLAHS???SSD2832?????
	{
		while(buffer1[16+j] != 0xffffffff)
		{
			buffer[Timing_Data_Max + (j*3)] 			= (u8)(buffer1[16+j]>>16);
			buffer[Timing_Data_Max + (j*3) + 1] 	= (u8)(buffer1[16+j]>>8);
			buffer[Timing_Data_Max + (j*3)	+	2]  = (u8)(buffer1[16+j]);
			j++;
		}
		temp = Timing_Data_Max + (j*3);
		temp1 = 16+j+1;
		buffer[temp] = 0xff;
		j = 0;
		while(buffer1[temp1+j] != 0xffffffff)
		{
			buffer[temp+j+1] = (u8)(buffer1[temp1+j]);
			j++;
		}
		buffer[temp+j+1] = 0xff;
		File_length = temp+j+2;	
	}
	else if(buffer[Timing_Data_Max-1] == 0x55)      //RGB ??SPI??
	{
		temp = Timing_Data_Max;
		temp1 = 16;
		j = 0;
		while(buffer1[temp1+j] != 0xffffffff)
		{
			buffer[temp+j] = (u8)(buffer1[temp1+j]);
			j++;
		}
		buffer[temp+j] = 0xff;
		File_length = temp+j+1;	
	}		
	//************?FLash??????PC,????********************
	//***************************************************************

	STM2PC_FilConfig(pdev,CDC_IN_EP,USB_Rx_Buffer[0],Uart_rx_flag,buffer,File_length,Uart_Error_None);
	//****************************************************************
}
	double vci_l,vddio_l,dvdd_l;
int f0,f1,f2;
OLED_Para OLED_Para_Process(u32* buf)
{

    OLED_Para Para;
	Para.DisMode = (((u8)(buf[12]>>24)&0x0f) < 2) ? 0 : 1;
	Para.H_pixel = (!Para.DisMode) ? (buf[8]>>24)+((buf[8]>>8)&0xff00) :2*((buf[8]>>24)+((buf[8]>>8)&0xff00));
	Para.V_pixel = (u16)(((buf[8]>>8)&0x00FF)+(buf[8]<<8));
	Para.pixel_clk = (float)((((buf[12]>>16)&0x00ff)|((buf[12]&0xff00)))/10.0);
	Para.SigMode = (u8)(buf[12]>>24)&0XF0;		//当前的 模组 信号格式		 //0x0n：MCU  0x1n：MIPI  0x2n：SPI3 0x3n：SPI4
	Para.PHYMode = (u8)(buf[12]&0x01);
	
	vci_l=(double)((u8)(buf[14]>>16))/60;
	vddio_l=(double)((u8)(buf[14]>>8))/60;	
	dvdd_l=(double)((u8)(buf[14]))/60;
	
	RDAC = (double)((1544-440.1*vci_l))/(vci_l-1.816)-1;
	RDAC_VDDIO = (double)((978.6-415.8*vddio_l))/(vddio_l-1.197)-1;
	RDAC_DVDD = (double)((352.7-173.5*dvdd_l))/(dvdd_l-0.798)-1;
	
	VDD_AD5274_5271_Init(RDAC);
	VDDIO_AD5274_5271_Init(RDAC_VDDIO);	
	if(dvdd_l == 0)
	{
		DVDD_EN_LOW;
	}
	else 
	{
		DVDD_EN_HIGH;
		DVDD_AD5274_5271_Init(RDAC_DVDD);
	}	
	
	if(Para.SigMode == 0x20)
	{
		Para.SigMode = 0x20;
		DUAL_SPI_MODE_AUTO = 0x00;
	}
	else if(Para.SigMode == 0x30)
	{
		Para.SigMode = 0x20;
		DUAL_SPI_MODE_AUTO = 0X01;
	}
	else if(Para.SigMode == 0x40)
	{
		Para.SigMode = 0x20;
		DUAL_SPI_MODE_AUTO = 0x02;
	}
	else if(Para.SigMode == 0x50)
	{
		Para.SigMode = 0x30;
		DUAL_SPI_MODE_AUTO = 0x03;
	}
	else if(Para.SigMode == 0x60)
	{
		Para.SigMode = 0x30;
		DUAL_SPI_MODE_AUTO = 0X04;
	}
	else if(Para.SigMode == 0x70)
	{
		Para.SigMode = 0x30;
		DUAL_SPI_MODE_AUTO = 0x05;
	}
	
	//Trim_Initial_Data(Para.SigMode,buf);		//整理FLASH里面的  初始化代码
	printf(" 当前显示模式是：%s\t%dx%d\r\n",((Para.SigMode == Video_Mode) ? "Mipi+SPI": ((Para.SigMode == CMD_Mode) ? "Command" : ((Para.SigMode == SPI3_Mode) ? "SPI3": "SPI4"))),Para.H_pixel,Para.V_pixel); 
	printf(" 像素时钟为 %.2fMHz \r\n",Para.pixel_clk);
    return Para;
}
/********************************************
功能： 将NandFlash或者SD卡里面的所有图片 判断是否为当前分辨率图片
参数1：Disc：磁盘标志  Nand_Disc/All_Disc
参数2：H_Size：水平分辨率
参数3：V_Size：垂直分辨率
返回： 符合当前分辨率的图片数量
*********************************************/
u8 BMP_Name_Process(u8 Disc,u16 H_Size,u16 V_Size)		//图片分辨率 处理，整理出和配置文件的分辨率相对应的 BMP图片
{
	u16 BMP_HP,BMP_VP;                                          //BMP图片的 水平和垂直分辨率
	u8 Current_BMP = 0;         //图片名称 处理时的 变量
	u8 Num = 0;
	if(PicCnt > 0)
	{
		for(;;)
		{
			if(Disc == All_Disc)
			{
				res = f_open(&sd_file,	FileNames[Current_BMP],FA_OPEN_EXISTING|FA_READ);	//打开 U盘中的BMP图片
			}
			if(res == FR_OK)	
			{   
				if(Disc == All_Disc)
				res=f_read(&sd_file,buffer,54,&br);		//读取BMP图片的前面54个数据，里面包含了BMP图片的一些参数
																								// 18,19,20,21是BMP图片的水平大小																			// 28,29 是BMP的颜色深度  (29<<8)+28=32,表示颜色深度是32位
				BMP_HP = (buffer[19]<<8)+(buffer[18]);	//BMP图片水平大小
				BMP_VP = (buffer[23]<<8)+(buffer[22]);	//BMP图片垂直大小
				
				//判断该BMP图片的尺寸是否和当前配置文件的模组尺寸大小一致
				if((BMP_VP == V_Size)&&(BMP_HP==H_Size))
				{	
					memcpy(valid_FileNames[Num],FileNames[Current_BMP],File_NAME_MAX);
					Num ++;
					printf(" %s\r\n",FileNames[Current_BMP]);
				}
				if((Current_BMP+1) < PicCnt)
					Current_BMP ++ ;
				else
				{
					Current_BMP = 0;
					break;
				}							
			}
//				if(Disc == Nand_Disc)
//						fclose(fout);	//关闭文件指针
//				else
				if(Disc == All_Disc)
					f_close(&sd_file);	//关闭文件指针
		}
	}
    return Num;
}
u8 Updata_cfg(char* cfg_name,u32 Address)
{	
	u32 k=0;
	//u16 SSD_ID = 0;
	u8 error_time=0;
	char *CFG_N=NULL;
	res = f_open(&sd_file,cfg_name,FA_OPEN_EXISTING|FA_READ);	//打开 U盘配置文件
	
	if(res == FR_OK)		//里面有配置文件，需要将配置文件拷贝到芯片FLASH 
	{	
        res = f_read(&sd_file,buffer, Timing_Data_Max,&br);//读数据，（文件指针，数据存放指针，需要读取的量，正确读出的量）
        if(((buffer[0] == 0x47)&&(buffer[1] == 0x56)&&(buffer[2] == 0x4f)&&(buffer[3] == 0x43)&&(buffer[4] == 0x6F)&&(buffer[5] == 0x6E))||(CFG_Valid_flag == 1))//????????"GVOConfig.cfg"
        {		
						error_time++;
            if(error_time<10)
            {
                CFG_Valid_flag = 1;
                OLED.SigMode = buffer[Timing_Data_Max-15-1] & 0xf0;
        
                for(i = 0;i<(Timing_Data_Max)/4;i++)	//将文件标识和Timing数据转换，byte的长度是64，因为FLASH存储是字存储，需要将byte转换成4个byte的字
                {
                    Timing_and_InitCode[i] =((uint32_t)buffer[i*4]<<24)+((uint32_t)buffer[(i*4)+1]<<16)+((uint32_t)buffer[(i*4)+2]<<8)+((uint32_t)buffer[(i*4)+3]);
										buffer1[k++] = Timing_and_InitCode[i];
								}
									//OLED = OLED_Para_Process(buffer1);
                f_lseek(&sd_file,Timing_Data_Max);
                res = f_read(&sd_file,buffer,512,&br);//读数据，（文件指针，数据存放指针，需要读取的量，正确读出的量）

                if((OLED.SigMode == Video_Mode)||(OLED.SigMode == CMD_Mode))
                {
                    for (i = 0; i < 512; i++)		//将2832的配置数据转换成字
                    {
                        if (buffer[i * 3] == 0xff)
                        {
														SSD2832_SCM_Flag=0;
                            Length++;
                            break;                    
                        }
												else if (buffer[i * 3] == 0xfe) //find up SCM setting
												{
													SSD2832_SCM_Flag=1;  //SCM setting send flag
													Length++;
													break;    
												}
                        //    0x H H H H  :   31:24->00(没有作用)   23:16->寄存器地址    15:0->寄存器值(高位在前)
                        SSD28xx_Code[SSD28xxCode_count] = ((uint32_t)buffer[i * 3]<<16) + ((uint32_t)buffer[i * 3 + 1]<<8) + ((uint32_t)buffer[i * 3 + 2]);
                        buffer1[k++] = SSD28xx_Code[SSD28xxCode_count] ;
												Length += 3;
                        SSD28xxCode_count ++;																						
                    }
                    SSD28xx_Code[SSD28xxCode_count]=0xffffffff;		        //该数据区分SSD2832配置代码和 DriverIC初始化代码		
										buffer1[k++] = SSD28xx_Code[SSD28xxCode_count] ; 	
					//---------------------------------------------------------------------------------
										if(SSD2832_SCM_Flag ==1) //SCM setting send Start
										{
											for ( ; i < 512; i+=2)		//将2832 SCM配置数据转换成字
											{
												if (buffer[i * 3 + 1] == 0xff)
												{
														break;                    
												}
												//    0x H H H H = 0x H H H H H H H H :   31:24->00(没作用)   23:16->(没作用)    15:0->寄存器值(CMD MSB ; CMD LSB)
												SSD28xx_SCM_Cmd[SSD28xx_SCM_Code_count]=((uint32_t)buffer[(i * 3 + 1)]<<8) + ((uint32_t)buffer[(i * 3 + 1) + 1]);
												//    0x H H H H = 0x H H H H H H H H :   31:24->data3   23:16->data2    15:0->寄存器值(data1 data0)
												SSD28xx_SCM_Data[SSD28xx_SCM_Code_count]=((uint32_t)buffer[(i * 3 + 1) + 2]<<24)+((uint32_t)buffer[(i * 3 + 1) + 3]<<16) + ((uint32_t)buffer[(i * 3 + 1) + 4]<<8) + ((uint32_t)buffer[(i * 3 + 1) + 5]);
												buffer1[k++] = SSD28xx_SCM_Cmd[SSD28xx_SCM_Code_count];
												buffer1[k++] = SSD28xx_SCM_Data[SSD28xx_SCM_Code_count];
												SSD28xx_SCM_Code_count++;
												Length += 6;						
											}
											Length = Length+1;
											SSD28xx_SCM_Data[SSD28xx_SCM_Code_count]=0xffffffff;		        //该数据区分SSD2832配置代码和 DriverIC初始化代码		
											buffer1[k++] = SSD28xx_SCM_Data[SSD28xx_SCM_Code_count] ; 			
										}
                }				
                f_lseek(&sd_file,Timing_Data_Max+Length);
                if(1)	//死循环，一直朝FLASH搬数据，知道数据搬完跳出死循环?
                {		
                    res = f_read(&sd_file,buffer,8192,&br);//读数据，（文件指针，数据存放指针，需要读取的量，正确读出的量）
                   // if(res||br == 0)	//读数据，（文件指针，数据存放指针，需要读取的量，正确读出的量）
                   // break;
                    
                    for (i = 0; i < 8192; i += (Code_length+1))
                    {
                        Code_length = buffer[i];	//每一句初始化代码的 数据长度
                        if (Code_length == 0xff)	//判断长度有255说明 ，到初始化代码的最后
                        {
													break;
                        }
                        Timing_and_InitCode[0] =	Code_length;	//数组中的[0]：这一句初始化代码的数据长度										
                        buffer1[k++] = Timing_and_InitCode[0];
												for (j = 1; j < Code_length+1; j++)	//递增将 初始化代码写入到数组
												{											
													Timing_and_InitCode[j] = ((uint32_t)buffer[i+j]);
													buffer1[k++] = Timing_and_InitCode[j] ;
                        }
                        InitCode_count ++;	//即将写下一个数组(下一句初始化代码)																											
                    }
										//若初始化超过8192字节
										if(Code_length != 0xff)
										{
											Code_length=0;
											f_lseek(&sd_file,Timing_Data_Max+Length+8192);
											res = f_read(&sd_file,buffer,8192,&br);//读取额外8192字节数据量
											for (i = 0; i < 8192; i += (Code_length+1))
											{
												Code_length = buffer[i];	//每一句初始化代码的 数据长度
												if (Code_length == 0xff)	//判断长度有255说明 ，到初始化代码的最后
												{
													break;
												}
												Timing_and_InitCode[0] =	Code_length;	//数组中的[0]：这一句初始化代码的数据长度										
												buffer1[k++] = Timing_and_InitCode[0];
												for (j = 1; j < Code_length+1; j++)	//递增将 初始化代码写入到数组
												{											
													Timing_and_InitCode[j] = ((uint32_t)buffer[i+j]);
													buffer1[k++] = Timing_and_InitCode[j] ;
												}
												InitCode_count ++;	//即将写下一个数组(下一句初始化代码)																											
											}
										}
						
                    Timing_and_InitCode[0]=0xffffffff;
										buffer1[k] = Timing_and_InitCode[0] ;
                }                    
						}	
						else
						{
							return 2;
						}						
				}
        else
        {            
            return 3;
        }
  }
	else
	{
		for(i=0;i<100;i++)      //让红灯 连续闪烁100次
		{
			LED2_HIGH;
			delay_ms(50);
			LED2_LOW;
			delay_ms(50);
		}
		return 1;
	}
	f_close(&sd_file);	//关闭文件指针
    return 0;
}

void Updata_cfg_printf(u8(*pf)(char*,u32),char* cfg_name,u32 Address)
{
	switch(pf(cfg_name,Address))
	{
		case 0 : printf (" PGConfig%d 更新成功!\r\n",cfg_name[11]-48);   break;
		case 1 : printf (" PGConfig%d 更新失败!\t打开文件异常\r\n",cfg_name[11]-48);   break;
		case 2 : printf (" PGConfig%d 更新失败!\t擦除FLASH异常\r\n",cfg_name[11]-48);   break;
		case 3 : printf (" PGConfig%d 更新失败!\t配置文件异常\r\n",cfg_name[11]-48);   break;
		case 4 : printf (" PGConfig%d 更新失败!\t写入FLASH异常\r\n",cfg_name[11]-48);   break;
		default: printf (" PGConfig%d 更新失败!\t其他异常\r\n",cfg_name[11]-48);   break;
	}
    SSD28xxCode_count = 0;
//		SSD28xx_SCM_Code_count = 0;
    InitCode_count = 0;
}

void Panel_ON(u8 signal_mode,u32* buf)			
{
	//u16 SSD_ID = 0;     
	u16 i = 16;			
	if((signal_mode == Video_Mode)||(signal_mode == CMD_Mode))  //Mipi mode为笔误实际指的是video mode
	{  		
		while(buf[i] != 0xFFFFFFFF)	
		{
			SSD28xx_Code[0] = buf[i];
			i++;
			if((SSD28xx_Code[0]&0x00B70001)!=0x00B70001) //send the 2832cfg reg ,if not inter mipi hs mode, 
			{	
				if((u8)(SSD28xx_Code[0]>>16)==0xBB)
				{
					if(OLED.PHYMode == C_PHY)
					{
						SSD2828_W_Reg_u32(signal_mode,CS1_2,0xBB,(0x0607<<16)+(u16)SSD28xx_Code[0]);   //BB[28]
						delay_ms(1);
						SSD2828_W_Reg(signal_mode,CS1_2,0xD3,0x0040);//D3[6] CMD_BC broadcast the 2c/3c content from MIPITX0 to MIPITX1
						delay_ms(1);
					}
					else if(OLED.PHYMode == D_PHY)
					{
						SSD2828_W_Reg_u32(signal_mode,CS1_2,0xBB,(0x1607<<16)+(u16)SSD28xx_Code[0]);
						delay_ms(1);
						SSD2828_W_Reg(signal_mode,CS1_2,0xD3,0x0000);
						delay_ms(1);
					}
				}
				else
				{
					SSD2828_W_Reg(signal_mode,CS1_2,(u8)(SSD28xx_Code[0]>>16),(u16)SSD28xx_Code[0]);
					delay_ms(1);
				}	
			}			
		}
		i++;	
		//------------------------ if SSD2832_SCM_Flag ="1"
		if(SSD2832_SCM_Flag==1)
		{
			while(buf[i] != 0xFFFFFFFF)	
			{
				SSD28xx_SCM_Cmd[0] = buf[i++];
				SSD28xx_SCM_Data[0] = buf[i++];
				if(OLED.PHYMode == C_PHY)
				{
					SSD2828_W_SCM_Reg_u32(signal_mode ,CS1_2, (u16)SSD28xx_SCM_Cmd[0] ,(u32)SSD28xx_SCM_Data[0]);
					delay_ms(1);
				}
			}
			i++;
		}
		delay_ms(50);
			
		//------------------------ 
	}
	while(buf[i] != 0xFFFFFFFF) //initial code 
	{
		InitCode_valid[0][0] = (u8)buf[i];		
		for(j=1;j<buf[i]+1;j++)												
			InitCode_valid[0][j] = (u8)buf[i+j];
		i += (buf[i]+1);
		if((OLED.SigMode == Video_Mode)||(OLED.SigMode == CMD_Mode))		
		{		
			SSD2828_W_Array(signal_mode,CS1_2,InitCode_valid[0],0);
			delay_ms(1);
			if(InitCode_valid[0][1]==0x11 && InitCode_valid[0][0] == 0x01)
			{
				delay_ms(120);
			}
		}
		else if((OLED.SigMode == SPI3_Mode)||(OLED.SigMode == SPI4_Mode))
		{
			SPI_PANEL_Write_u8_Array(signal_mode,CS1_2,(u8 *)InitCode_valid[0]);
		}
	}
	if((OLED.SigMode == Video_Mode)||(OLED.SigMode == CMD_Mode))		
	{
		SSD2828_W_Reg(signal_mode,CS1_2,(u8)(SSD28xx_Code[0]>>16),(u16)SSD28xx_Code[0]);//inter hs mode
		delay_ms(5);
		FSMC_Pure_colour(WHITE); 
		Load_done_HIGH;
	}
	else if((OLED.SigMode == SPI3_Mode)||(OLED.SigMode == SPI4_Mode))
	{
		SPI_Write_u8_Cmd(OLED.SigMode,CS1_2,0x11);
		delay_ms(120);
		SPI_Write_u8_Cmd(OLED.SigMode,CS1_2,0x29);
		delay_ms(20);  
	}
}



/********************************************
功能： 通过FSMC发送DDR3存数数据的首地址
参数1：BMP_Addr_ID：首地址
返回： 无
*********************************************/
void FSMC_DDR_Addr(u8 BMP_Addr_ID)
{	
    //将即将发送的BMP存放的DDR3地址发送出去  
    write_cmd(0x3456);	
    write_cmd((u16)(((BMP_Addr_ID*OLED.V_pixel*OLED.H_pixel)*8/5)>>16));	
    write_cmd((u16)((BMP_Addr_ID*OLED.V_pixel*OLED.H_pixel)*8/5));	  
    write_cmd(0x6543); 
}
/********************************************
功能： 通过FSMC将NandFLash中的图片数据发送到FPGA
参数1：valid_BMP_Count：图片序号
返回： 0：成功   1：失败
*********************************************/
u8 FSMC_BMP_Data(float pclk,u8 valid_BMP_Count)
{							
	res = f_open(&sd_file,	valid_FileNames[valid_BMP_Count] ,FA_OPEN_EXISTING|FA_READ);  //读SD卡
    if(res == FR_OK)
    {	
        j=1;
		f_lseek(&sd_file,54L);			
        for(;;)
        {                
            if(OLED.H_pixel % 4 != 0)
			    f_lseek(&sd_file,((OLED.V_pixel)-j)*(OLED.H_pixel*3+(OLED.H_pixel % 4))+54);
            else
				f_lseek(&sd_file,((OLED.V_pixel)-j)*OLED.H_pixel*3+54);     
            if(OLED.DisMode == 1)
            {
				res = f_read(&sd_file,buffer1, OLED.H_pixel*3/4,&br);
                if(br == 0)
                    break; 

                for(i=0;i<OLED.H_pixel/8;i++)     //左右半屏 点亮屏幕
                {                                                              
                    Write_DATA(buffer1[i*3]&0x0000FFFF);
                    Write_DATA(((buffer1[i*3]>>16)&0x000000FF)  + ((buffer1[i*3+(OLED.H_pixel/8)*3]&0x000000FF)<<8));                     
                    Write_DATA(((buffer1[i*3+(OLED.H_pixel/8)*3]&0x00FFFF00)>>8));
                    
                    Write_DATA(((buffer1[i*3]>>24)&0x000000FF)  + ((buffer1[1+i*3]&0x000000FF)<<8));
                    Write_DATA(((buffer1[1+i*3]>>8)&0x000000FF)  + ((buffer1[i*3+(OLED.H_pixel/8)*3]&0xFF000000)>>16)); 
                    Write_DATA(buffer1[1+i*3+(OLED.H_pixel/8)*3]&0x0000FFFF); 
                    
                    Write_DATA((buffer1[1+i*3]&0xFFFF0000)>>16);
                    Write_DATA(((buffer1[2+i*3])&0x000000FF)  + ((buffer1[1+i*3+(OLED.H_pixel/8)*3]&0x00FF0000)>>8));
                    Write_DATA((((buffer1[1+i*3+(OLED.H_pixel/8)*3])&0xFF000000)>>24)  + ((buffer1[2+i*3+(OLED.H_pixel/8)*3]&0x000000FF)<<8));
                    
                    Write_DATA(((buffer1[2+i*3]&0x00FFFF00)>>8));
                    Write_DATA(((buffer1[2+i*3]&0xFF000000)>>24)  + (buffer1[2+i*3+(OLED.H_pixel/8)*3]&0x0000FF00)); 
                    Write_DATA((buffer1[2+i*3+(OLED.H_pixel/8)*3]&0xFFFF0000)>>16);                         
                }  
            }		
            else if(OLED.DisMode == 0)
            {
                 //br = fread(buffer1,sizeof(uint32_t), (OLED.H_pixel*3+(OLED.H_pixel % 4))/4, fout); 
				res = f_read(&sd_file,buffer1,(OLED.H_pixel*3+(OLED.H_pixel % 4)),&br);
                if(br == 0)
                    break; 
                for(i = 0;i<(br/4);i++)
                {
                    Write_DATA((u16)buffer1[i]); 
                    delay_6ns((pclk < 50) ? 50 : 0);
                    if(i == (br/4-1)) //最后一条特别处理
                    {
                        if((OLED.H_pixel % 4) == 0)
                        {
                            Write_DATA((u16)(buffer1[i]>>16));
                            delay_6ns((pclk < 50) ? 50 : 0);
                        }      
                    }   
                    else
                    {
                        Write_DATA((u16)(buffer1[i]>>16));
                        delay_6ns((pclk < 50) ? 50 : 0);
                    }
                }
            }
//#if BMP_GROWTH == 1                 
            j++;
            if(j == OLED.V_pixel+1)
            break;
//#endif                
        }
        f_close(&sd_file);	//关闭文件指针
    }
    else
    {
        f_close(&sd_file);	//关闭文件指针
        return 1;
    }			   
    return 0;
}

void FSMC_Send_BMP(float pclk,u8 DDR_Add_ID,u8 valid_BMP_Count)
{
	static u8 i=0;
	
	FSMC_DDR_Addr(DDR_Add_ID);
	if(FPGA_ID == 1) FSMC_BMP_NUM (DDR_Add_ID); //当前画面序号
	if(i<Loaded_BMPNum)
	{
		FSMC_BMP_Data(pclk,valid_BMP_Count);
		i++;
	}
//	else
//	{
//		delay_ms(1000);
//	}
	if(FPGA_ID == 0) FSMC_BMP_NUM (DDR_Add_ID); //当前画面序号
}

void WorkStation(void)
{
	if(!KEY_DEBUG_STATE)	//开机的时候，有某个按键按下的话，则进入Debug模式
	{
		Working_Mode = Debug_Mode;
	/*	
		if(!GPIO_ReadInputDataBit(KEYPeriph_GPIO,KEY1)) 			//UP按键  HFZ_PLAY
        {
            if(!GPIO_ReadInputDataBit(KEY3Periph_GPIO,KEY3))       // DOWN按键
			NAND_EraseChip();
        }
     */   
        Device_ID_Buf[0] = 0;
        Device_Addr = Device_Flash_Addr;
        do
        {
            Device_ID = Device_ID_Buf[0];
            FLASH_If_Read(Device_Addr, Device_ID_Buf, 0,1);	//将FLASH的模组Timing数据读取出来，准备发送给FPGA
        }
        while(Device_ID_Buf[0] != 0xFFFFFFFF);
        if((Device_ID == 0)||(Device_ID > 20))
            Device_ID = 1;
        Device_Addr -= 4;
        FPGA_RESET_LOW;			//FPGA复位
        LED_HIGH;	
		MX_USB_DEVICE_Init();	//初始化USB 	
	}
	else
	{
		if(SD_Init()!=0)  //若!=0 ,检测不到SD卡
		{
			LED4_LOW;
		}
		if(f_mount(&SD_fatfs,SD_Path,1) == FR_OK)
		{
			disk = All_Disc;
			printf(" SD卡设备已插入\r\n");
			CFG_Num = CFG_Copy();
		}
		else disk = Nand_Disc;
  
		if(disk == All_Disc)
		{
			Updata_cfg_printf(Updata_cfg,CFG_Name[0],WriteAddress);  
		}

		scan_files(disk,1);	//枚举存储器里所有的BMP图片，将磁盘里的BMP图片的名称全部拷贝到数组里面成功
		OLED = OLED_Para_Process(buffer1);
		Loaded_BMPNum=BMP_Name_Process(disk,OLED.H_pixel,OLED.V_pixel);	//BMP图片分辨率 归类

		if(Loaded_BMPNum == 0)      //里面没有合适的图片就 只显示RGB WB
		{
			Loaded_BMPNum = sizeof Pure_Color_Table/sizeof Pure_Color_Table[0];
			Pure_Color_Flag = 1;   
		}
		else Pure_Color_Flag = 0;

		if((OLED.SigMode == Video_Mode)||(OLED.SigMode == CMD_Mode))
		{	           
			FPGA_ResetProcess();
			Load_done_LOW;      
			ICS307_Valid_Data = calculate_idt307_config(OLED.pixel_clk);	
			ICS307_ValidClk_Set(ICS307_Valid_Data);          
			FSMC_OLED_Parameter(buffer1,OLED.SigMode);
		}
    }
}

int main(void)
{ //---恭喜你看到这行注释---
	//main函数只负责基本的初始化，负责接收上位机发送数据包的解析过程在“usbd_cdc.c"这个文件内的"USBD_CDC_DataOut"函数里面
	
	bool first_round=false;
	u8 temp = 100;
	u8  First_Conf = 0;
	u32 VCP_Receive_BIN_True_num = 0;	
	Cache_Enable();                 //打开L1-Cache
	HAL_Init();	//初始化HAL库	
//外部晶振为25M的时候,推荐值:plln=432,pllm=25,pllp=2,pllq=9.
//得到:Fvco=25*(432/25)=432Mhz
//     Fsys=432/2=216Mhz
//     Fusb=432/9=48Mhz
	Stm32_Clock_Init(432,25,2,9);   //设置时钟,216Mhz 
	delay_init(216);                //延时初始化
	uart1_init(115200);		        //串口初始化		
	HardWare_Init();      	
	WorkStation();
	//ssd id	
	Set_2828_reset(OLED.SigMode);       //复位2832
	//Set_panel_reset(); //复位OLED模组
	SSD2832_ID = SSD2828_R_Reg(OLED.SigMode,CS1_2,0xB0);
	FPGA_ID = FPGA_ID_Gain();
	
	while(1)    
	{
		if(Working_Mode == Debug_Mode)  //
		{    	
			if(USB_ReceivedCount>0)
			{      
				if(SendTo_PC_cfgFile)           //返回配置文件到PCsw标志
				{
					SendTo_PC_cfgFile=0;
					USB_StatusDataSended=0;
					WriteAddress = Inter_Flash_Addr;
					Generate_cfg(&USB_OTG_dev,WriteAddress);
					while(USB_StatusDataSended == 0)
					{
						delay_us(1);
					}
				} 
				else if(Receive_BIN_Flag1)
				{
					Receive_BIN_Flag1 = 0;
					Receive_BIN_Flag = 1;
					VCP_Receive_BIN_True_num = 0;							
				}

				else if(Receive_CFG_Flag1 == 1)
				{
					if(initSD(CFGorBMP,BMPnums) == 1)
					{
						Receive_CFG_Flag1 = 2;
					}
				}
				else if((Receive_CFG_Flag1 == 2)&&(USB_ReceivedCount>0))
				{
						CFGBMP_W(USB_Rx_Buffer,CFG_Lenth,USB_ReceivedCount,CFGorBMP,BMPnums);
						CFG_Lenth = CFG_Lenth + USB_ReceivedCount;
						if(CFG_Lenth == Receive_CFG_Length)
						{
							Receive_CFG_Flag1 = 0;
							CFG_Lenth = 0;
							Receive_CFG_Length = 0;
							f_mount(NULL,"0:",1);
							USB_Rx_Buffer[0] = 0x55;
							USB_Rx_Buffer[1] = 0x01;
							USB_Rx_Buffer[2] = 0x02;
							USB_Rx_Buffer[3] = 0x09+CFGorBMP;
							STM2PC(&USB_OTG_dev,CDC_IN_EP,USB_Rx_Buffer,USB_Rx_Buffer[2]+3);           //返回 写寄存器状态  ：ok
						}
						else
						{
							USB_Rx_Buffer[0] = 0xFe;
							USB_Rx_Buffer[1] = 0x01;
							USB_Rx_Buffer[2] = 0x02;
							USB_Rx_Buffer[4] = 0;
							STM2PC(&USB_OTG_dev,CDC_IN_EP,USB_Rx_Buffer,USB_Rx_Buffer[2]+3); 
						}

				}
				else if((NUM==0)&&(Receive_BIN_Flag == 1))
				{
					if(VCP_Receive_BIN_True_num == 0)
					{
						for(int k=0;k<=250;k++)
						{
							W25QXX_Erase_Sector(k);
						}
					}
					VCP_Receive_BIN_True_num+=USB_ReceivedCount;
					if(VCP_Receive_BIN_True_num<Receive_BIN_Length)
					{
						DataToBuff(USB_Rx_Buffer,DataFlag*512,USB_ReceivedCount);
						delay_ms(10);
						DataFlag++;
						if(USB_ReceivedCount!=512) DataFlag = 4;
						if(DataFlag == 4)
						{
							DataFlag = 0;
							Flash_Program(Page);
							delay_ms(100);
							Page++;
						}
						if(Page == 640)
						{
							Page =0;
						}
						USB_Rx_Buffer[0] = 0xFe;
						USB_Rx_Buffer[1] = 0x01;
						USB_Rx_Buffer[2] = 0x02;
						USB_Rx_Buffer[4] = Uart_Error_None;
						STM2PC(&USB_OTG_dev,CDC_IN_EP,USB_Rx_Buffer,USB_Rx_Buffer[2]+3);           //返回 写寄存器状态  ：ok
						//delay_ms(5);
					}
					else if(VCP_Receive_BIN_True_num==Receive_BIN_Length)   //最后一笔
					{
						DataToBuff(USB_Rx_Buffer,DataFlag*512,USB_ReceivedCount);
						delay_ms(10);
						Flash_Program(Page);
						delay_ms(100);
						BIN_Len[0] = Receive_BIN_Length>>24;
						BIN_Len[1] = Receive_BIN_Length>>16;
						BIN_Len[2] = Receive_BIN_Length>>8;
						BIN_Len[3] = Receive_BIN_Length;
						//	W25QXX_Read(datatemp,250,0,128);
						DataToBuff_Len((u8 *)BIN_Len,0,4);
						delay_ms(10);

						//												
						Flash_Program(250);
						delay_ms(10);
						//											W25QXX_Read(datatemp,640,0,128);
						USB_Rx_Buffer[0] = 0x55;
						USB_Rx_Buffer[1] = 0x01;
						USB_Rx_Buffer[2] = 0x02;
						USB_Rx_Buffer[3] = 0x01;
						STM2PC(&USB_OTG_dev,CDC_IN_EP,USB_Rx_Buffer,USB_Rx_Buffer[2]+3);           //返回 写寄存器状态  ：ok
						delay_ms(100);
						//NVIC_SystemReset();
						HAL_NVIC_SystemReset();
					}
				}
				USB_ReceivedCount=0;	
			}
		}      
		else //
		{   
            if(First_Conf == 0)
            {
                First_Conf = 1;
				Panel_ON(OLED.SigMode,buffer1);
                Valid_BMP_No = 0;
                EXTIInit(); 
                EXIT_Enable(Enable);
//              LED_Flick = LED_Flick_Slow;
                __HAL_TIM_ENABLE(&TIM3_Handler); //使能定时器3 
  //            LED2_HIGH; 
                Key_Auto = 1;
				Auto_Flag = 1;
		//		FSMC_Pure_colour(Pure_Color_Table[Valid_BMP_No]);
		//		delay_ms(100);
            }

            if(Key_vaild)					//按键有效按下状态
            {    
                FSMC_Send_Flag = 0;
                Key_vaild = 1;
                Delay_time = 0;
				EXIT_Enable(DISABLE);
                if(OLED.SigMode == Video_Mode)		//配置文件中信号格式 是Mipi(video)模式
                {     
					#if DSI_Set_Window_EN == 1                    
						SSD2832_Set_Window(OLED.SigMode,CS1_2,(OLED.H_pixel==390) ? 4 : 0,(OLED.H_pixel==390) ? OLED.H_pixel+4 : OLED.H_pixel,0,OLED.V_pixel);
					#endif                  
                    if(Pure_Color_Flag == 1)
                        FSMC_Pure_colour(Pure_Color_Table[Valid_BMP_No]);
                    else
					FSMC_Send_BMP(OLED.pixel_clk,DDR_Addr_ID,Valid_BMP_No);
                    Load_done_HIGH;			//图片载入完成                    
                }   
                else if(OLED.SigMode == CMD_Mode) 
                {   
					#if DSI_Set_Window_EN == 1                    
                    SSD2832_Set_Window(OLED.SigMode,CS1_2,(OLED.H_pixel==390) ? 4 : 0,(OLED.H_pixel==390) ? OLED.H_pixel+4 : OLED.H_pixel,0,OLED.V_pixel);
					#endif
                    if(Pure_Color_Flag == 1)
                        SSD2828_W_RAM_Pic(OLED.pixel_clk,OLED.SigMode,CS1_2,OLED.H_pixel,OLED.V_pixel,(Pure_Color_Table[Valid_BMP_No]&0xff0000)>>16,(Pure_Color_Table[Valid_BMP_No]&0x00ff00)>>8,Pure_Color_Table[Valid_BMP_No]&0x0000ff); 
                    else if(temp!=Valid_BMP_No)
                    {     
						temp = Valid_BMP_No;
                        SSD2828_W_Reg(OLED.SigMode,CS1_2,0xBC,(u16)(OLED.H_pixel*OLED.V_pixel*3)); 
                        SSD2828_W_Reg(OLED.SigMode,CS1_2,0xBD,(u16)((OLED.H_pixel*OLED.V_pixel*3)>>16)); 
						if(OLED.H_pixel == 450)//2020.12.23 临时补丁： 6.8" VESA 10bit ，BEh设定值Hactive 450未能被12整除，设480则正常。
						{
							SSD2828_W_Reg(OLED.SigMode,CS1_2,0xBE,(u16)(480));
						}
						else if(OLED.H_pixel*3<=4095)
						{
							SSD2828_W_Reg(OLED.SigMode,CS1_2,0xBE,(u16)(OLED.H_pixel*3));//(OLED.H_pixel*3)); 
						}			
						else
						{
							SSD2828_W_Reg(OLED.SigMode,CS1_2,0xBE,(u16)(OLED.H_pixel*3/2)); 
						}                   
                        SSD2828_W_Cmd(OLED.SigMode,CS1_2,0xBF);
                        SSD2828_W_Cmd(OLED.SigMode,CS1_2,0X2C);                            
                   //     fout = fopen (valid_FileNames[Valid_BMP_No],"r");        //以只读的方式 打开 Nandflash 里的图片
						res = f_open(&sd_file,	valid_FileNames[Valid_BMP_No],FA_OPEN_EXISTING|FA_READ);//U盘读取
                        for(i=0;i<OLED.V_pixel;i++)
                        {   
							#if BMP_GROWTH == 1 		
							f_lseek(&sd_file,((OLED.V_pixel-1)-i)*(OLED.H_pixel*3+(OLED.H_pixel % 4))+54);
							#else 
                            //fseek (fout, i*(OLED.H_pixel*3+(OLED.H_pixel % 4))+54, SEEK_SET);            
							#endif
                          //  br = fread(buffer,sizeof(uint8_t), OLED.H_pixel*3, fout);  
							res = f_read(&sd_file,buffer, OLED.H_pixel*3,&br);													
                            SPI_CS_Select(CS1_2,0); 
                            SSD2828_W_RAM_buffer_8bits_part(OLED.pixel_clk,OLED.SigMode,buffer,OLED.H_pixel,1,0);
                            SPI_CS_Select(CS1_2,1);
                        }
                       // fclose(fout); 
						f_close(&sd_file);
                    }                        
                }
                else if((OLED.SigMode == SPI3_Mode)||(OLED.SigMode == SPI4_Mode))
                {
					#if SPI_Set_Window_EN == 1                     
                   // SPI_Set_Window(OLED.SigMode,CS1_2,0, OLED.H_pixel-1,0, OLED.V_pixel-1);
					#endif                  
                    if(Pure_Color_Flag == 1)
                        SPI3_PANEL_WriteRAM(OLED.SigMode,CS1_2,OLED.H_pixel,OLED.V_pixel,(Pure_Color_Table[Valid_BMP_No]&0xff0000)>>16,(Pure_Color_Table[Valid_BMP_No]&0x00ff00)>>8,Pure_Color_Table[Valid_BMP_No]&0x0000ff,DUAL_SPI_MODE_AUTO,1);
                    else
                    {
//                        SPI_Write_code(OLED.SigMode,CS1_2 ,0xFE,0x01);
//                        SPI_Write_code(OLED.SigMode,CS1_2 ,0x04,0x80);
//                        SPI_Write_code(OLED.SigMode,CS1_2 ,0xFE,0x00);
//                        SPI_Write_code(OLED.SigMode,CS1_2 ,0xC4,0x31);        // SP3T 2Wire

                      //  fout = fopen (valid_FileNames[Valid_BMP_No],"r");        //以只读的方式 打开 Nandflash 里的配置文件
						res = f_open(&sd_file,valid_FileNames[Valid_BMP_No],FA_OPEN_EXISTING|FA_READ);
                       // fseek (fout, 54L, SEEK_SET);
						f_lseek(&sd_file,54L);	
                        for(j=0;j<OLED.V_pixel;j++)
                        {
							#if BMP_GROWTH == 1
							// fseek (fout, ((OLED.V_pixel-1)-j)*(OLED.H_pixel*3)+54, SEEK_SET);
							f_lseek(&sd_file,((OLED.V_pixel-1)-j)*(OLED.H_pixel*3 + (OLED.H_pixel%4))+54);
							#endif 	
							//br = fread(buffer,sizeof(uint8_t), OLED.H_pixel*3, fout);
							res = f_read(&sd_file,buffer, OLED.H_pixel*3,&br);
							SPI_PANEL_WriteRAM_buffer_part(OLED.SigMode,CS1_2,buffer,OLED.H_pixel,1,Rec_first_line_Flag,DUAL_SPI_MODE_AUTO,1);
							if(Rec_first_line_Flag == 1)
							Rec_first_line_Flag = 0;
                        }
                      //  fclose(fout);
						f_close(&sd_file);
                    }                        
                } 
                EXIT_Enable(Enable);
				if(Pure_Color_Flag == 1)
                {
                    switch(Pure_Color_Table[Valid_BMP_No])
                    {
                        case RED:   printf(" 当前画面：红\r\n");break;
                        case GREEN: printf(" 当前画面：绿\r\n");break;
                        case BLUE:  printf(" 当前画面：蓝\r\n");break;
                        case WHITE: printf(" 当前画面：白\r\n");break;
                        case BLACK: printf(" 当前画面：黑\r\n");break;
                        case YELLOW:printf(" 当前画面：黄\r\n");break;
                        case PINK:  printf(" 当前画面：紫\r\n");break;
                        case CYAN:  printf(" 当前画面：青\r\n");break;
                    }
                }                       
                else
                    printf(" 当前画面:%s\t\t\t用时：%d\r\n",valid_FileNames[Valid_BMP_No],Delay_time);	

                Count_time = Delay_time;
                Delay_time = 0; 
								
					if(Auto_Flag == 1)
					{
						if(Valid_BMP_No == (Loaded_BMPNum-1))		
							Valid_BMP_No = 0;
						else
							Valid_BMP_No ++;
						if(DDR_Addr_ID == Loaded_BMPNum - 1)
						{
							DDR_Addr_ID = 0;
							first_round = true;
						}
						else 
						{
							DDR_Addr_ID ++;
						}
						if(first_round==true)
							HAL_Delay(1000);//SD卡自动点屛时的切图延时设置
					}
					else
					{
						first_round = false;	
					}
					//LED2_LOW;  
				//EXIT_Enable(Enable);
				
                FSMC_Send_Flag = 1;                
            }				
        }
  }
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	EXIT_Enable(DISABLE);
	delay_ms(10);
    if(HAL_GPIO_ReadPin(KEY_DOWNPeriph_GPIO,KEY_DOWN) == 0)
		{
			delay_ms(300);
			if(HAL_GPIO_ReadPin(KEY_DOWNPeriph_GPIO,KEY_DOWN) == 1 && Auto_Flag!=1)
			{
				if(Valid_BMP_No == (Loaded_BMPNum-1))		
					Valid_BMP_No = 0;
				else
					Valid_BMP_No ++;
				if(DDR_Addr_ID == (Loaded_BMPNum-1))
					DDR_Addr_ID = 0;
				else DDR_Addr_ID ++;
			}
			else if(HAL_GPIO_ReadPin(KEY_DOWNPeriph_GPIO,KEY_DOWN) == 0)
			{
				delay_ms(1000);
				if(HAL_GPIO_ReadPin(KEY_DOWNPeriph_GPIO,KEY_DOWN) == 0)
				{
				//切换
				if(Auto_Flag == 1)
					Auto_Flag =0;
				else Auto_Flag =1;
				}
			}
		}	
	else if(HAL_GPIO_ReadPin(KEY_UPPeriph_GPIO,KEY_UP) == 0)
	{
		delay_ms(300);
		if(HAL_GPIO_ReadPin(KEY_UPPeriph_GPIO,KEY_UP) == 1 && Auto_Flag!=1)
		{
			if(Valid_BMP_No == 0)		
				Valid_BMP_No =  Loaded_BMPNum - 1;
			else	
				Valid_BMP_No --;
			if(DDR_Addr_ID == 0)
				DDR_Addr_ID = Loaded_BMPNum - 1;
			else
				DDR_Addr_ID --;
		}
		else if(HAL_GPIO_ReadPin(KEY_UPPeriph_GPIO,KEY_UP) == 0)
		{
			delay_ms(1000);
			if(HAL_GPIO_ReadPin(KEY_UPPeriph_GPIO,KEY_UP) == 0)
			{
				//切换
				if(Auto_Flag == 1)
					Auto_Flag = 0;
				else Auto_Flag =1;
			}
		}
	}
	EXIT_Enable(Enable);
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
